﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IGolovkine.AoA
{
    public static class Disposable
    {
        public static readonly IDisposable Empty = Disposable.Create(()=> {});

        public static IDisposable Create(Action action)
        {
            return new AnonymousDisposable(action);
        }

        public static IDisposable Combine(IDisposable disposable, params IDisposable[] disposables)
        {
            if (disposables.Length != 0)
            {
                return CombineInternal(Enumerable.Concat(Enumerable.Repeat(disposable, 1), disposables));
            }
            else
            {
                return disposable;
            }
        }

        public static IDisposable Combine(IEnumerable<IDisposable> disposables)
        {
            return CombineInternal(disposables);
        }

        private static IDisposable CombineInternal(IEnumerable<IDisposable> disposables)
        {
            return new AnonymousDisposable(() =>
            {
                Lazy<List<Exception>> lazyResult = new Lazy<List<Exception>>();

                try
                {
                    foreach (IDisposable disposable in disposables)
                    {
                        if (disposable != null)
                        {
                            disposable.Dispose();
                        }
                    }
                }
                catch (Exception ex)
                {
                    lazyResult.Value.Add(ex);
                }

                if (lazyResult.IsValueCreated)
                {
                    throw new AggregateException(lazyResult.Value);
                }
            });
        }

        private struct AnonymousDisposable : IDisposable
        {
            private readonly Action _action;
            public AnonymousDisposable(Action action)
            {
                _action = action;
            }

            void IDisposable.Dispose()
            {
                _action();
            }
        }
    }
}
